// * isValidMfAbbrName - 验证厂商/厂别简称
// * isValidRealName - 验证真实中英文名
// * isValidUserName - 验证用户名
// * isValidPassword - 验证密码(正则验证，必须由大写字母、小写字母、数字及特殊符号组成，6-20个字符)
// * isValidStrictPassword - 验证严格密码(必须由大写字母、小写字母、数字及特殊符号中的至少三种组成，8-20个字符)
// * isValidPhone - 验证手机号码
// * isValidEmail - 验证邮箱
// * isValidInt32 - 验证32位整型
// * isValidDecimal - 验证小数位数(不能超过几位)，最多不能超过12
// * isValidDecimalAny - 仅验证是不是小数，不管小数位多少
// * isValidDate - 验证日期，格式为yyyy-MM-dd, yyyy/MM/dd, yyyyMMdd, yy-MM-dd, yy/MM/dd, yyMMdd
// * isValidTime - 验证时间，格式为HH:mm，HH:mm:ss
// * isValidDatetime - 验证日期时间，格式为yyyy-MM-dd HH:mm，yyyy-MM-dd HH:mm:ss
// * isValidProductionDate - 验证生产日期，支持格式有yyyyMMdd和yyyyWW两种
// * extraPasswordRepeatCheck - 在isValidStrictPassword的前提下，判断密码是否存在重复和连续的多个字符，返回""表示没问题否则是问题的描述

import _, {parseInt} from 'lodash'

import {ValidateFunctionsDef} from './validate-functions.d'
import i18n from '../i18n/i18n'

const {t} = i18n.global

const isValidMfAbbrName = function (value: string) {
  return $f.regex.regMfAbbrName.test(value)
}

const isValidRealName = function (value: string) {
  return $f.regex.regRealName.test(value)
}

const isValidUserName = function (value: string) {
  return $f.regex.regUserName.test(value)
}

const isValidPassword = function (value: string) {
  return $f.regex.regPassword.test(value)
}

const isValidStrictPassword = function (value: string) {
  if (value.length < 8 || value.length > 20) {
    return false
  }
  let flagUpperCase = 0
  let flagLowerCase = 0
  let flagNumber = 0
  let flagSpecialCharacter = 0
  const specialCharacters = '~!@#$%^&*().,+-=:<>/?;|[]_'
  for (let i = 0; i < value.length; i++) {
    const c = value.charAt(i)
    if (c >= 'A' && c <= 'Z') {
      flagUpperCase = 1
    } else if (c >= 'a' && c <= 'z') {
      flagLowerCase = 1
    } else if (c >= '0' && c <= '9') {
      flagNumber = 1
    } else if (specialCharacters.indexOf(c) !== -1) {
      flagSpecialCharacter = 1
    } else {
      return false
    }
  }
  return flagUpperCase + flagLowerCase + flagNumber + flagSpecialCharacter >= 3
}

const isValidPhone = function (value: string) {
  return $f.regex.regPhone.test(value)
}

const isValidEmail = function (value: string) {
  return $f.regex.regEmail.test(value)
}

const isValidInt32 = function (value: string) {
  if (!/^[+-]?(0|[1-9]\d{0,9})$/.test(value)) {
    return false
  }
  const intVal = parseInt(value)
  return intVal >= -0x80000000 && intVal <= 0x7FFFFFFF
}

const isValidDecimal = function (value: number | string, decimalNum: number) {
  if (decimalNum > 12) {
    decimalNum = 12
  }
  if (decimalNum < 0 || !decimalNum) {
    decimalNum = 0
  }
  if (_.isFinite(value)) {
    return _.round(<number>value, decimalNum) === value
  } else if (typeof (value) === 'string') {
    if (!/^[+-]?\d+(\.\d{1,12})?$/.test(value)) {
      return false
    }
    const decPointPos = value.indexOf('.')
    if (decPointPos >= 0) {
      return value.length - decPointPos - 1 <= decimalNum
    }
    return true
  } else {
    return false
  }
}

const isValidDecimalAny = function (value: number | string) {
  if (_.isFinite(value)) {
    return true
  } else if (typeof (value) === 'string') {
    return /^[+-]?\d+(\.\d+)?$/.test(value)
  } else {
    return false
  }
}

const _isValidDate = function(year:number, month:number, day:number){
  if (year > 2099 || year < 1900 || month > 12 || month < 1 || day > 31 || day < 1) {
    return false
  }
  if ((month === 4 || month === 6 || month === 9 || month === 11) && day > 30) {
    return false
  }
  if (month === 2) {
    if ((year % 100 === 0 && year % 400) || (year % 100 && year % 4 === 0)) {
      if (day > 29) {
        return false
      }
    } else {
      if (day > 28) {
        return false
      }
    }
  }
  return true
}

const isValidDate = function (value: Date | string, multi: boolean) {
  if (_.isDate(value)) {
    return true
  } else { // must be string
    let intYear
    let intMonth
    let intDay
    if (/^\d{4}([-\/])\d{2}([-\/])\d{2}$/.test(value)) {
      // "yyyy-MM-dd" "yyyy/MM/dd"
      intYear = parseInt(value.substring(0, 4))
      intMonth = parseInt(value.substring(5, 7))
      intDay = parseInt(value.substring(8, 10))
    } else if (multi && /^\d{2}\/\d{2}\/\d{2}$/.test(value)) {
      // "yy/MM/dd"
      intYear = parseInt(value.substring(0, 2)) + 2000
      intMonth = parseInt(value.substring(3, 5))
      intDay = parseInt(value.substring(6, 8))
    } else if (multi && /^(\d{8})$/.test(value)) {
      // "yyyyMMdd"
      intYear = parseInt(value.substring(0, 4))
      intMonth = parseInt(value.substring(4, 6))
      intDay = parseInt(value.substring(6, 8))
    } else if (multi && /^(\d{6})$/.test(value)) {
      // "yyMMdd"
      intYear = parseInt(value.substring(0, 2)) + 2000
      intMonth = parseInt(value.substring(2, 4))
      intDay = parseInt(value.substring(4, 6))
    } else {
      return false
    }
    return _isValidDate(intYear, intMonth, intDay)
  }
}

const _isValidTime = function(hour:number, minute:number, second?:number){
  return hour>=0 && hour<=23 && minute>=0 && minute<=59 && (second==undefined || second>=0 && second<=59)
}

const isValidTime = function (value: string, withSec?: boolean) {
  let intHour
  let intMinute
  let intSecond
  //尝试根据HH:mm:ss去解
  if((withSec===true || withSec===undefined) && /^\d{2}:\d{2}$/.test(value)){
    intHour = parseInt(value.substring(0, 2))
    intMinute = parseInt(value.substring(3, 5))
    return _isValidTime(intHour, intMinute)
  }
  //尝试根据HH:mm去解
  if((withSec===false || withSec===undefined) && /^\d{2}:\d{2}:\d{2}$/.test(value)){
    intHour = parseInt(value.substring(0, 2))
    intMinute = parseInt(value.substring(3, 5))
    intSecond = parseInt(value.substring(6, 9))
    return _isValidTime(intHour, intMinute, intSecond)
  }
  return false
}

//只支持这两种格式：yyyy-MM-dd HH:mm 和 yyyy-MM-dd HH:mm:ss
const isValidDatetime = function (value: string, withSec?:boolean){
  if(withSec && value.length!=19 || !withSec && value.length!=16){
    return false
  }
  if (/^\d{4}-\d{2}-\d{2}\s\d{2}:\d{2}(:\d{2})?$/.test(value)) {
    // "yyyy-MM-dd" "yyyy/MM/dd"
    const intYear = parseInt(value.substring(0, 4))
    const intMonth = parseInt(value.substring(5, 7))
    const intDay = parseInt(value.substring(8, 10))
    const intHour = parseInt(value.substring(11, 13))
    const intMinute = parseInt(value.substring(14, 16))
    let intSecond = undefined
    if(withSec){
      intSecond = parseInt(value.substring(17,19))
    }
    return _isValidDate(intYear, intMonth, intDay) && _isValidTime(intHour, intMinute, intSecond)
  }
  return false
}

const isValidProductionDate = function (value: string, len?: 6 | 8) {
  if (value.length === 6 && (!len || len === 6)) {
    return $f.regex.regYYYYWW.test(value)
  }
  if (value.length === 8 && (!len || len === 8)) {
    return $f.regex.regYYYYMMDD.test(value)
  }
  return false
}

const charDict1: Map<string, number>= new Map([
  ['1', 1],
  ['2', 2],
  ['3', 3],
  ['4', 4],
  ['5', 5],
  ['6', 6],
  ['7', 7],
  ['8', 8],
  ['9', 9],
  ['0', 10],
  ['a',12],['A',12],
  ['b',13],['B',13],
  ['c',14],['C',14],
  ['d',15],['D',15],
  ['e',16],['E',16],
  ['f',17],['F',17],
  ['g',18],['G',18],
  ['h',19],['H',19],
  ['i',20],['I',20],
  ['j',21],['J',21],
  ['k',22],['K',22],
  ['l',23],['L',23],
  ['m',24],['M',24],
  ['n',25],['N',25],
  ['o',26],['O',26],
  ['p',27],['P',27],
  ['q',28],['Q',28],
  ['r',29],['R',29],
  ['s',30],['S',30],
  ['t',31],['T',31],
  ['u',32],['U',32],
  ['v',33],['V',33],
  ['w',34],['W',34],
  ['x',35],['X',35],
  ['y',36],['Y',36],
  ['z',37],['Z',37]
])
const charDict2: Map<string, number>= new Map([
  ['0', 0],
  ['1', 1],
  ['2', 2],
  ['3', 3]
])
const kbDict1 : Map<string, number>= new Map([
  ['~', 0],
  ['1', 1],['!', 1],
  ['2', 2],['@', 2],
  ['3', 3],['#', 3],
  ['4', 4],['$', 4],
  ['5', 5],['%', 5],
  ['6', 6],['^', 6],
  ['7', 7],['&', 7],
  ['8', 8],['*', 8],
  ['9', 9],['(', 9],
  ['0', 10],[')', 10],
  ['-', 11],['_', 11],
  ['=', 12],['+', 12],
  ['q', 14],['Q', 14],
  ['w', 15],['W', 15],
  ['e', 16],['E', 16],
  ['r', 17],['R', 17],
  ['t', 18],['T', 18],
  ['y', 19],['Y', 19],
  ['u', 20],['U', 20],
  ['i', 21],['I', 21],
  ['o', 22],['O', 22],
  ['p', 23],['P', 23],
  ['[', 24],['{', 24],
  [']', 25],['}', 25],
  ['\\',26],['|', 26],
  ['a', 28],['A', 28],
  ['s', 29],['S', 29],
  ['d', 30],['D', 30],
  ['f', 31],['F', 31],
  ['g', 32],['G', 32],
  ['h', 33],['H', 33],
  ['j', 34],['J', 34],
  ['k', 35],['K', 35],
  ['l', 36],['L', 36],
  [';', 37],[':', 37],
  ['z', 39],['Z', 39],
  ['x', 40],['X', 40],
  ['c', 41],['C', 41],
  ['v', 42],['V', 42],
  ['b', 43],['B', 43],
  ['n', 44],['N', 44],
  ['m', 45],['M', 45],
  [',', 46],['<', 46],
  ['.', 47],['>', 47],
  ['/', 48],['?', 48]
  ])
const kbDict2 : Map<string, number>= new Map([
  ['1', 1],['!', 1],
  ['q', 2],['Q', 2],
  ['a', 3],['A', 3],
  ['z', 4],['Z', 4],
  ['2', 5],['@', 5],
  ['w', 6],['W', 6],
  ['s', 7],['S', 7],
  ['x', 8],['X', 8],
  ['3', 9],['#', 9],
  ['e', 10],['E', 10],
  ['d', 11],['D', 11],
  ['c', 12],['C', 12],
  ['4', 13],['$', 13],
  ['r', 14],['R', 14],
  ['f', 15],['F', 15],
  ['v', 16],['V', 16],
  ['5', 17],['%', 17],
  ['t', 18],['T', 18],
  ['g', 19],['G', 19],
  ['b', 20],['B', 20],
  ['6', 17],['^', 17],
  ['y', 18],['Y', 18],
  ['h', 19],['H', 19],
  ['n', 20],['N', 20],
  ['7', 21],['&', 21],
  ['u', 22],['U', 22],
  ['j', 23],['J', 23],
  ['m', 24],['M', 24],
  ['8', 25],['*', 25],
  ['i', 26],['I', 26],
  ['k', 27],['K', 27],
  [',', 28],['<', 28],
  ['9', 29],['(', 29],
  ['o', 30],['O', 30],
  ['l', 31],['L', 31],
  ['.', 32],['>', 32],
  ['0', 33],[')', 33],
  ['p', 34],['P', 34],
  [';', 35],[':', 35],
  ['/', 36],['?', 36]
])

// 返回""表示没问题，否则返回问题的描述
function extraPasswordRepeatCheck(password: string) {
  let repeatCount = 0
  let prevChar = '\0'

  // CharSeq已经出现连续的数量
  const charDicts: Map<string, number>[] = [charDict1,charDict2] // 假设charDicts是一个字典数组
  const charSeqCountArr: number[] = Array(charDicts.length).fill(0)
  const prevCharSeqIdxArr: number[] = Array(charDicts.length).fill(-1)
  const charSeqFlags: (boolean | null)[] = Array(charDicts.length).fill(null)

  // KbSeq已经出现连续的数量
  const kbDicts: Map<string, number>[] = [kbDict1,kbDict2] // 假设kbDicts是一个字典数组
  const kbSeqCountArr: number[] = Array(kbDicts.length).fill(0)
  const prevKbSeqIdxArr: number[] = Array(kbDicts.length).fill(-1)
  const kbSeqFlags: (boolean | null)[] = Array(kbDicts.length).fill(null)

  const chars: string[] = password.split('')

  for (const c of chars) {
    // 连续重复字符判断
    if (prevChar === c) {
      repeatCount++;
      if (repeatCount > 3) {
        return t('不可出现连续3个以上的重复字符')
      }
    } else {
      prevChar = c
      repeatCount = 1
    }
    // 处理连续次序的字符
    for (let i = 0; i < charDicts.length; i++) {
      const charDict: Map<string, number> = charDicts[i]
      let charSeqIdx = charDict.get(c)
      if(charSeqIdx === undefined){
        charSeqIdx =-1;
      }
      const diff: number =  charSeqIdx - prevCharSeqIdxArr[i]
      if (diff === 1 || diff === -1) {
        if (diff === 1) {
          if (charSeqFlags[i] === true || charSeqFlags[i] === null && charSeqCountArr[i] === 1) {
            charSeqCountArr[i]++
            charSeqFlags[i] = true
          } else {
            charSeqCountArr[i] = 1
            charSeqFlags[i] = true
          }
        } else { // diff === -1
          if (charSeqFlags[i] === false || charSeqFlags[i] === null && charSeqCountArr[i] === 1) {
            charSeqCountArr[i]++
            charSeqFlags[i] = false
          } else {
            charSeqCountArr[i] = 1
            charSeqFlags[i] = false
          }
        }
        if (charSeqCountArr[i] > 3) {
          return t('不可出现3个以上的连续字符')
        }
      } else {
        charSeqCountArr[i] = 1
        charSeqFlags[i] = null
      }
      prevCharSeqIdxArr[i] = charSeqIdx !== undefined ? charSeqIdx : -1
    }

    // 处理连续键盘序的字符
    for (let i = 0; i < kbDicts.length; i++) {
      const kbDict: Map<string, number> = kbDicts[i]
      let kbSeqIdx  = kbDict.get(c)
      if(kbSeqIdx === undefined){
        kbSeqIdx = -1
      }
      const diff: number =  kbSeqIdx - prevKbSeqIdxArr[i]
      if (diff === 1 || diff === -1) {
        if (diff === 1) {
          if (kbSeqFlags[i] === true || kbSeqFlags[i] === null && kbSeqCountArr[i] === 1) {
            kbSeqCountArr[i]++
            kbSeqFlags[i] = true
          } else {
            kbSeqCountArr[i] = 1
            kbSeqFlags[i] = true
          }
        } else { // diff === -1
          if (kbSeqFlags[i] === false || kbSeqFlags[i] === null && kbSeqCountArr[i] === 1) {
            kbSeqCountArr[i]++
            kbSeqFlags[i] = false
          } else {
            kbSeqCountArr[i] = 1
            kbSeqFlags[i] = false
          }
        }
        if (kbSeqCountArr[i] > 3) {
          return t('不可出现3个以上的键盘序的字符')
        }
      } else {
        kbSeqCountArr[i] = 1
        kbSeqFlags[i] = null
      }
      prevKbSeqIdxArr[i] = kbSeqIdx !== undefined ? kbSeqIdx : -1
    }
  }

  return '';
}
export default {
  isValidMfAbbrName,
  isValidRealName,
  isValidUserName,
  isValidPassword,
  isValidStrictPassword,
  isValidPhone,
  isValidEmail,
  isValidInt32,
  isValidDecimal,
  isValidDecimalAny,
  isValidDate,
  isValidTime,
  isValidDatetime,
  isValidProductionDate,
  extraPasswordRepeatCheck
} as ValidateFunctionsDef
